final static int sizeX = 200;
final static int sizeY = 200;

int CPM = 32;
int rate = 10;   // update rate in ms
color black = color(0,0,0);
color white = color(255,255,255);

int NPos;
float dt = 0.010;   // delta time in seconds
float a = 200; // acceleration
float v0 = 20;   //
float dm = 0.1; // size in metre of a pixel
int[] pos = new int[sizeY];
int Npos = 0;

void computePositions()
{
  pos[0] = 0;
  Npos = 1;
  int k = 1;
  float t = k*dt;
  float nextPos = (0.5*a*t*t + v0*t)/dm;
  while (nextPos < sizeY && k < sizeY)
  {
    pos[k] = int(nextPos);
    Npos++;
    println(Npos + " " + nextPos + " " + pos[k]);
    // update
    k++;
    t = k*dt;
    nextPos = (0.5*a*t*t + v0*t)/dm;
  }
}

void setup()
{
  size(sizeX,sizeY);

  println("Starting up");
  computePositions();

  init_pixels();
}

void draw()
{
  update_pixels();
  delay(rate);
}

void update_pixels()
{
  // load the pixels
  loadPixels();

  // fall data one row
  for (int r=Npos-1 ; r > 0 ; r--)
    for (int k=0 ; k < pos[2] ; k++)
      for (int c=0 ; c < sizeX ; c++)
      {
        if (pos[r]+k >= sizeY)
          continue;
        pixels[(pos[r]+k)*sizeX + c] = pixels[(pos[r-1]+k)*sizeX + c];
      }

  // draw random particles for the new line
  float p = CPM*rate/(sizeX*60000.0);
  for (int c=0 ; c < sizeX ; c++)
  {
    float rng = random(1);
    // all in black
    for (int r=0 ; r < pos[2] ; r++)
      pixels[r*sizeX + c] = black;
    // one per column in white at random
    int r = int(random(0,pos[2]-1));
    if (rng < p)
      pixels[r*sizeX + c] = white;
  }

  // update pixels
  updatePixels();
}

void init_pixels()
{
  loadPixels();
  for (int p=0 ; p < sizeX*sizeY ; p++)
    pixels[p] = black;
  updatePixels();
}
